package org.lgiavedoni.android.franq.service.log;

import java.io.PrintWriter;
import java.io.StringWriter;

import org.lgiavedoni.android.franq.core.log.Log;
import org.lgiavedoni.android.franq.core.log.dao.LogDAO;
import org.lgiavedoni.android.franq.core.service.Service;
import org.lgiavedoni.android.franq.service.analytic.AnalyticService;
import org.lgiavedoni.android.franq.service.communication.CommunicationService;
import org.lgiavedoni.android.franq.service.config.ConfigService;
import org.lgiavedoni.android.franq.service.config.ConfigService.ConfigKey;
import org.lgiavedoni.android.franq.service.phone.ContextService;

public class Logger extends Service {

	public static final Logger inst = new Logger();
	private LogLevel currenLevel = LogLevel.DEBUG;

	public static enum LogLevel {
		DEBUG(1, "debug"), INFO(3, "info"), WARNING(6, "warning"), ERROR(10, "error");
		private long value;
		private String text;

		private LogLevel(long value, String text) {
			this.value = value;
			this.text = text;
		}

		@Override
		public String toString() {
			return text;
		}
	}

	private Logger() {
		currenLevel = getLogLevel(ConfigService.inst.getValue(ConfigKey.LOG_LEVEL));
	}

	public LogLevel getLogLevel(String level) {
		for (LogLevel logLevel : LogLevel.values()) {
			if (logLevel.text.equals(level.toLowerCase())) {
				return logLevel;
			}
		}
		return null;
	}

	public void log(String text, LogLevel level) {
		if (currenLevel.value <= level.value) {
			if (isStarted()) {
				if (LogLevel.ERROR.equals(level)) {
					System.err.println(level.text.toUpperCase() + ": " + text);
					if (CommunicationService.inst != null) {
						try {
							CommunicationService.inst.sendDefaultTextMessage(text);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				} else {
					System.out.println(level.text.toUpperCase() + ": " + text);
				}
			}
			if (ContextService.inst.isApplicationContextLoaded()) {
				// Phone (only errors)
				if (LogLevel.ERROR.equals(level)) {
					LogDAO.inst.add(new Log(level, text));
					AnalyticService.inst.trackError(text);
				}
			} else {
				// Desktop
				LogDAO.inst.add(new Log(level, text));
			}

		}
	}

	public void log(Throwable ex, LogLevel level) {
		StringWriter sw = new StringWriter();
		ex.printStackTrace(new PrintWriter(sw));
		log(sw.toString(), level);
	}

	public void log(String text, Throwable ex, LogLevel level) {
		StringWriter sw = new StringWriter();
		ex.printStackTrace(new PrintWriter(sw));
		log(text + " - " + sw.toString(), level);
	}

	public void debug(String text) {
		log(text, LogLevel.DEBUG);
	}

	public void debug(Exception ex) {
		log(ex, LogLevel.DEBUG);
	}

	public void warning(String text) {
		log(text, LogLevel.WARNING);
	}

	public void warning(Throwable ex) {
		log(ex, LogLevel.WARNING);
	}

	public void info(String text) {
		log(text, LogLevel.INFO);
	}

	public void error(String text) {
		log(text, LogLevel.ERROR);
	}

	public void error(String text, Exception ex) {
		ex.printStackTrace();
		log(text, ex, LogLevel.ERROR);
	}

	public void error(Throwable ex) {
		try {
			log(ex, LogLevel.ERROR);
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	public boolean setLogLevel(String level) {
		if (getLogLevel(level) == null)
			return false;
		debug("Changing the log leve form [" + currenLevel + "] to [" + level + "]");
		this.currenLevel = getLogLevel(level);
		return true;
	}

	@Override
	public String getServiceName() {
		return "logger";
	}

	@Override
	protected void startInternal() {
	}

	@Override
	protected void stopInternal() {
		// Do nothing
	}

	@Override
	public void _run() {
		// Do nothing
	}
}
